package elephant.rpc.server.core;

import java.lang.reflect.InvocationTargetException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import elephant.rpc.server.message.RPCMessage;
import elephant.rpc.server.message.RPCRequest;
import elephant.rpc.server.service.RPCServiceManager;
import elephant.utils.DumpUtil;

/**
 * 
 * @author skydu
 *
 */
public class RPCThreadWorker implements Runnable{
	//
	private PerformMonitor performMonitor;
	private RPCServiceManager serviceManager;
	private RPCRequest req; 
	//
	private static Logger logger=LoggerFactory.getLogger(RPCThreadWorker.class);
	//
	public RPCThreadWorker(PerformMonitor performMonitor,RPCServiceManager serviceManager,RPCRequest req){
		this.performMonitor=performMonitor;
		this.serviceManager=serviceManager;
		this.req=req;
	}

	@Override
	public void run() {
		invokeMethod();
	}

	private void invokeMethod() {
		long startTime=System.currentTimeMillis();
		RPCMessage msg=req.getMessage();
		//dump parermeter
		if(logger.isInfoEnabled()){
			logger.info(">>>invokeMethod:#{}@{}>{}",
					RPCMessage.getServiceClass(msg),
					RPCMessage.getMethodName(msg),
					msg.id);
		}
		if(logger.isDebugEnabled()){
			String traceName="#"+msg.id+
					"@"+">"+
					RPCMessage.getServiceClass(msg)+"."+RPCMessage.getMethodName(msg);
			logger.debug(DumpUtil.dumpParameter(traceName,msg.parameters));
		}
		//
		RPCMessage rsp=null;
		Throwable exception=null;
		try{
			Object ret=serviceManager.invoke(
					RPCMessage.getServiceClass(msg),
					RPCMessage.getMethodName(msg),
					msg.parameterTypes,
					msg.parameters);
			rsp=RPCMessage.createRspMsg(msg.id, ret, 0, null, null);
		}catch (Throwable e){
			if(e instanceof InvocationTargetException){
				exception = ((InvocationTargetException)e).getTargetException();
			}else{
				exception = e;
			}
		} finally{
			long endTime=System.currentTimeMillis();
			long useTime=endTime-startTime;
			boolean isException=false;
			//
			if (exception!=null) {
				isException=true;
				if(exception instanceof BizException){
					BizException be=(BizException)exception;
					logger.warn("<invoke:{},biz exception code={},msg={}" ,
							RPCMessage.getMethodName(msg),
							be.getCode(),
							be.getMessage());
					rsp=RPCMessage.createRspMsg(msg.id, null, be.getCode(), be.getMessage(), null);
				}else{
					rsp=RPCMessage.createRspMsg(msg.id, null, 0, null, new RuntimeException(exception.getMessage()));
					logger.error("<invoke:" + RPCMessage.getMethodName(msg), exception);		
				}
			}
			if(logger.isInfoEnabled()){
				logger.info("<<<invokeMethod:{}#{}@{}> time:{}ms",
						msg.id,
						RPCMessage.getServiceClass(msg),
						RPCMessage.getMethodName(msg),
						(endTime-startTime));
			}
			//
			if(!msg.isAsync){
				req.getSession().write(rsp);
			}
			//
			performMonitor.invokeMethod(useTime,isException);
		}
	}
}
